/* Hello World Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>

#include "duktape.h"


static void quickmcu_fatal_handler(void *udata, const char *msg) {
    (void) udata;  /* ignored in this case, silence warning */

    /* Note that 'msg' may be NULL. */
    fprintf(stderr, "*** FATAL ERROR: %s\n", (msg ? msg : "no message"));
    fflush(stderr);
    /* abort(); */
}

static duk_ret_t simple_print(duk_context *ctx)
{
	duk_push_string(ctx, " ");
	duk_insert(ctx, 0);
	duk_join(ctx, duk_get_top(ctx) - 1);
	printf("%s\n", duk_safe_to_string(ctx, -1));
	return 0;
}

#include "__generated/gen_js.h"
#include "__generated/gen_jsinit.h"
void module_socket_init(duk_context *ctx);
void module_file_init(duk_context *ctx);
void module_bridge_init(duk_context *ctx);

int quickmcu_main()
{
    duk_context *ctx = duk_create_heap(NULL, NULL, NULL, NULL, quickmcu_fatal_handler);
    if (!ctx) {
        fprintf(stderr, "Failed to create a Duktape heap.\n");
        exit(1);
    }

    /* JS: print(str); */
    duk_push_c_function(ctx, simple_print, 1);
    duk_put_global_string(ctx, "print");

    /* init modules */
    genJSInit(ctx);
    module_file_init(ctx);

    /* boot */
    if(duk_peval_string(ctx, (char*) js_boot) != 0)
    {
        printf("eval failed: %s\n", duk_safe_to_stacktrace(ctx, -1));
        duk_pop(ctx);
    }
    
    if(duk_peval_string(ctx, (char*) js_shell) != 0)
    {
         printf("eval failed: %s\n", duk_safe_to_stacktrace(ctx, -1));
         duk_pop(ctx);
    }

    if(duk_peval_string(ctx, (char*) js_tft) != 0)
    {
         printf("eval failed: %s\n", duk_safe_to_stacktrace(ctx, -1));
         duk_pop(ctx);
    }
    
    if(duk_peval_string(ctx, (char*) js_net) != 0)
    {
        printf("eval failed: %s\n", duk_safe_to_stacktrace(ctx, -1));
        duk_pop(ctx);
    }
    
    if(duk_peval_string(ctx, (char*) js_http) != 0)
    {
        printf("eval failed: %s\n", duk_safe_to_stacktrace(ctx, -1));
        duk_pop(ctx);
    }

    /* callback */
    duk_eval_string(ctx, "mainLoop();");
    
    duk_destroy_heap(ctx);
    return 0;
}

void app_main()
{
    printf("Hello QuickMCU!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    quickmcu_main();
}
